﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Data;
using System.Data.SqlClient;
using System.Threading;
using System.Xml.Linq;
using System.Xml;

namespace ChatServer.model
{
    class ServerSocket : dbconn.DBConnector
    {
        //private variables used to loop threads for listening/sending

       
        //private list of Room objects. One object for each Room registered in Database
        private List<Room> _activeRooms;
        private List<User> _activeUsers;
  

        public ServerSocket()
        {
            //to fill _activeRooms, instantiate _activeRooms and call getRooms() method
            _activeRooms = new List<Room>();
            _activeUsers = new List<User>();
            GetRooms();
            
        }

        //login method made public for client access
        public bool Login(string userName, string ipAddress, string password)
        {
            //convert string IPAddress to IPAddress data type
            IPAddress address = IPAddress.Parse(ipAddress);
            return ValidateUser(userName, address, password);
        }

        //method for logging out made public for client access
        public void LogOut(string ipAddress)
        {
            //remove userSocket from each room
            foreach (Room room in _activeRooms)
            {
                IPAddress convIP = IPAddress.Parse(ipAddress);
                room.RemoveUser(convIP);
            }
        }

        //sendMessage method made public for client access
        public void SendMessage(string xml)
        {
            //recieve xml string and send through process message method
            ProcessIncomingMessage(xml);
        }

        private bool ValidateUser(string userName, IPAddress IPAddress, string userPassword)
        {
            //create new User by passing in parameters
            User u = new User(userName, userPassword);

            if (u.Authentication(userName, userPassword))
            {
                CreateUser(u, IPAddress);
                return true;

                //call method to push messages to all clients


            }
            else
                //garbage collection will take care of user object that is not used
                return false;
        }

        public void CreateUser(User u, IPAddress IPAddress)
        {
            //create new usersocket and append to room list and user
            UserSocket us = new UserSocket(IPAddress, 8733);
            UserSocketToRooms(us);
            u.addUserSocket(us);

            //add user to list of active users
            _activeUsers.Add(u);

            //create room messages for each user
            Chat creator = new Chat();
            XmlDocument messageDoc;

            foreach (User activeUser in _activeUsers)
            {
                //retrieve room permissions
                List<Room> listUserRooms = GetRoomPermissions(activeUser);

                //create message using permissable rooms
                foreach (Room room in listUserRooms)
                {
                    //create message for each room
                    messageDoc = creator.createRoomMessage(room, _activeUsers);

                    //after message creation, send out message to every user's userSocket
                    activeUser.UserSocket.sendMessage(messageDoc);
                }
 
            }

        }

        //method used for removing User 
        public void RemoveUser(IPAddress ipAddress)
        {
            //remove user from user list
            foreach (User user in _activeUsers)
            {
                if (IPAddress.Parse(user.UserSocket.UserUserSocket.RemoteEndPoint.ToString()) == ipAddress)
                {
                    _activeUsers.Remove(user);
                }
            }
            //create room messages for each user updating loss of user
            Chat creator = new Chat();
            XmlDocument messageDoc;

            foreach (User activeUser in _activeUsers)
            {
                //retrieve room permissions
                List<Room> listUserRooms = GetRoomPermissions(activeUser);

                //create message using permissable rooms
                foreach (Room room in listUserRooms)
                {
                    //create message for each room
                    messageDoc = creator.createRoomMessage(room, _activeUsers);
                    activeUser.UserSocket.sendMessage(messageDoc);
                }

                //after message creation, send out message to every user's userSocket

            }
        }
            
        //method will return list of rooms User is permissable in
        public List<Room> GetRoomPermissions(User user)
        {
            //create list of parameters for sp
            List<SqlParameter> listParams = new List<SqlParameter>();
            SqlParameter param1 = new SqlParameter("@userName", user.UserName);

            //add param to list
            listParams.Add(param1);

            //create list of room objects
            List<Room> roomList = new List<Room>();

            DataTable dt = this.SendDataTableRequest("GetRoomPermissions", listParams);

            if (dt != null)
            {
                foreach (DataRow dr in dt.Rows)
                {
                    //find roomInstance in current list of Rooms
                    foreach (Room activeRoom in _activeRooms)
                    {
                        if (activeRoom.RoomName == dr["roomName"].ToString())
                        {
                            //once found, add to list of permissable rooms
                            roomList.Add(activeRoom);
                            break;
                        }
                    }
                   
                }
            }
            else
            {
                throw new Exception("Get Rooms DataTable not created.");
            }
            
            return roomList;
        }
        public void GetRooms()
        {
            DataTable dt = this.SendDataTableRequest("GetRooms", new List<SqlParameter>());

            if (dt != null)
            {
                foreach (DataRow dr in dt.Rows)
                {
                    Room r = new Room(dr["roomName"].ToString());
                    _activeRooms.Add(r);
                }
            }
            else
            {
                throw new Exception("Get Rooms DataTable not created.");
            }
        }

        public void UserSocketToRooms(UserSocket us)
        {
            // Determine rooms based on permissions

            foreach (Room r in _activeRooms)
            {
                r.AppendSocket(us);
            }
        }

        private Room GetRoom(string roomName)
        {
            try
            {
                foreach (Room r in _activeRooms)
                {
                    if (r.RoomName == roomName)
                    {
                        return r;
                        
                    }
                }
                return null;
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        public void ProcessIncomingMessage(string xml)
        {
            Chat c = new Chat();
            c.parseXml(xml);
            try
            {
                //retrieve correct room depending on roomName of parsed message
                Room r = GetRoom(c.RoomName);

                //send message to all usersockets in that room
                XmlDocument doc = c.createChatMessage();
                r.ForwardMessage(doc); 
            }
            catch (Exception ex)
            {
                
            }

        }
   
    }
}
